#pragma once

namespace kratos {

// singleton
template <typename ClassType> class Singleton {
  Singleton() = delete;
  Singleton(const Singleton &) = delete;
  Singleton(Singleton &&) = delete;
  Singleton<ClassType> &operator=(const Singleton &) = delete;

private:
  /*thread_local*/ static ClassType *instance_; // The pointer of Singleton

public:
  // Returns the singleton instance pointer
  // @param args The argument for ctor of ClassType
  // @return singleton instance pointer
  template <typename... Args> static ClassType *instance(Args &&... args) {
    if (!instance_) {
      instance_ = new ClassType(std::forward<Args>(args)...);
    }
    return instance_;
  }

  // Destroy singleton
  static void destroy() {
    if (instance_) {
      delete instance_;
    }
    instance_ = nullptr;
  }
};

template <typename T> /*thread_local*/ T *Singleton<T>::instance_ = nullptr;

} // namespace kratos
